iT邦幫忙

2026 iThome 鐵人賽

DAY 10
0
佛心分享-SideProject30

30 天開發一款真正能每天使用的散步 App系列 第 10

推薦路線(1)——根據散步需求生成路線

  • 分享至 

  • xImage
  •  

完成自由散步與路線顯示後,接下來要實作的是「推薦散步路線」。

自由散步的流程比較單純,開始後持續記錄 GPS,結束時再計算距離、時間與速度即可。

但推薦散步不太一樣,在開始之前就要先知道使用者想怎麼走,例如:

  • 從哪裡出發
  • 想走多久或多遠
  • 是否回到起點
  • 想經過公園、咖啡店等地點

接下來要做的,就是把這些需求轉換成一條真正可以步行的路線。

整體架構

目前我先把推薦流程拆成以下幾個步驟:

  1. 使用者輸入需求
  2. App 將需求送到後端
  3. 後端整理距離、時間與偏好
  4. Google Places 搜尋附近地點
  5. 後端建立起點、終點與 waypoint
  6. Google Routes 計算實際可步行的道路
  7. 回傳路線並儲存結果

各層負責的內容如下:

元件 負責內容
React Native App 收集需求、顯示推薦路線
後端 整理需求、建立候選、呼叫 Google API
Google Places 搜尋附近符合偏好的地點
Google Routes 計算實際可步行的道路
資料庫 儲存推薦結果與路線資料

App 不會直接呼叫 Google Places 或 Google Routes,而是先把使用者輸入的條件送到後端:

type GenerateRouteRequest = {
  start: {
    latitude: number;
    longitude: number;
  };
  targetDurationSeconds?: number;
  targetDistanceMeters?: number;
  returnToStart: boolean;
  preferences: RoutePreference[];
};

真正困難的是決定要去哪裡

一開始我以為只要把散步條件交給 Google Routes,就能直接得到推薦路線。

但 Google Routes 解決的是「已經知道要去哪裡之後,該怎麼走」,並不會替我決定目的地。

推薦散步通常只有起點是確定的,而時間、距離和偏好都不是 Routes API 可以直接拿來決定目的地的條件,因此後端還需要先完成一段轉換:

30 分鐘
   ↓
預估散步距離
   ↓
Google Places 搜尋附近公園
   ↓
取得公園座標
   ↓
建立起點、終點與 waypoint
   ↓
交給 Google Routes 計算道路

Google Routes 除了起點與終點,也支援途中必須經過的 waypoint。

因此從 Places 找到合適的地點後,可以把這些地點整理成 waypoint,再交給 Routes 規劃真正的步行路線。

Routes 不會只是把這些座標用直線連起來,而是會根據實際道路與步行限制,計算出可以行走的路線。

先把時間換成參考距離

推薦路線支援兩種目標:

  • 想走多久
  • 想走多遠

如果使用者直接輸入距離,後端就可以直接拿這個距離作為後續規劃的參考。

但如果使用者只輸入時間,系統還不知道大概要搜尋多大的範圍,也不知道 waypoint 應該放多遠。

因此,我先使用固定步行速度 1.25 m/s,將時間換算成預估距離:

參考距離 = 目標時間 × 預估步行速度
const WALKING_SPEED_METERS_PER_SECOND = 1.25;

const targetDistance =
  request.targetDistanceMeters ??
  request.targetDurationSeconds! *
    WALKING_SPEED_METERS_PER_SECOND;

假如使用者想走 30 分鐘:

30 分鐘 = 1800 秒
1800 × 1.25 = 2250 公尺

這裡算出的 2250 公尺並不是最後真正會走的距離,而是後續產生候選路線時使用的參考值。

有了這個距離後系統才知道 Places 大概要搜尋多大的範圍,以及候選 waypoint 大概要落在哪裡。

用 Google Places 找到實際地點

有了參考距離後,如果使用者選擇了「公園」、「咖啡店」等偏好,就會先透過 Google Places 搜尋附近符合條件的地點。

例如:

偏好:公園
   ↓
Google Places
   ↓
大安森林公園
榮星花園
青年公園
...

Places API 回傳的不只是地點名稱,也包含每個地點的座標。

例如:

{
  "displayName": {
    "text": "大安森林公園"
  },
  "location": {
    "latitude": 25.0335,
    "longitude": 121.5356
  }
}

這裡真正需要的是地點的經緯度,後續才能拿來建立 waypoint。

建立 waypoint

取得地點座標後,就可以整理出後續規劃路線需要的起點、終點與 waypoint。

例如使用者選擇回到起點,路線可能會組成:

Origin
   ↓
Waypoint
   ↓
Destination(Origin)

也就是從起點出發,途中經過指定地點,最後再回到原本的起點。

如果不需要回到起點,則可以把最後一個候選地點當成 Destination,其餘地點再作為途中經過的 waypoint。

這些座標整理完成後,就可以交給 Google Routes 計算真正的步行道路。

把座標交給 Google Routes

在 Google Routes API 中,中途需要經過的 waypoint 會放在 intermediates 欄位裡。

因此需要先將前面整理好的 waypoint 轉成 API 需要的格式:

const intermediates = intermediateWaypoints.map(
  waypoint => ({
    location: {
      latLng: {
        latitude: waypoint.latitude,
        longitude: waypoint.longitude,
      },
    },
  }),
);

接著再將起點、終點與 intermediates 一起送給 Google Routes:

const response = await fetch(
  'https://routes.googleapis.com/directions/v2:computeRoutes',
  {
    ...
    body: JSON.stringify({
      origin: {
        location: {
          latLng: request.start,
        },
      },
      destination: {
        location: {
          latLng: destination,
        },
      },
      intermediates,
      travelMode: 'WALK',
    }),
  },
);

Routes API 會回傳規劃完成的路線,目前主要會使用三個欄位:

  • distanceMeters:實際道路距離
  • duration:預估步行時間
  • polyline.encodedPolyline:路線座標

到這裡,就完成了從使用者需求到實際步行路線的轉換:

使用者需求
   ↓
參考距離
   ↓
Google Places
   ↓
地點座標
   ↓
Waypoint
   ↓
Google Routes
   ↓
可步行路線

不過現在只是成功算出一條可以走的路線,還不能保證它就是最符合使用者需求的一條。

例如使用者想走 3 公里,實際算出的路線可能只有 1 公里,也可能超過 4 公里。

因此明天要分享的是如何挑出最適合的一條路線。


上一篇
基礎散步流程(5)——繪製路線簡圖
下一篇
推薦路線(2)——能走的路很多,該選哪一條?
系列文
30 天開發一款真正能每天使用的散步 App12
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言